package com.huawei.codearts.tools.aop;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.support.MultipartFilter;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@Aspect
@Component
public class ResultExceptionAspect implements Ordered {

    @Override
    public int getOrder() {
        return 1;  // 越小的值，优先级越高，越大的值优先级越低。
    }

    /**
     * Around切入点
     */
    @Pointcut("execution(* com.huawei.codearts.controller.*.*(..))")
    public void aroundPointcut() {
    }

    /**
     * 记录请求和响应日志的切面
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("aroundPointcut()")  // 环绕通知
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        Object[] args = joinPoint.getArgs();
        Object result;
        ObjectMapper mapper = new ObjectMapper();
        try {
            log.info("[result][info]日志记录，start...");
            long startTime = System.currentTimeMillis();
            result = joinPoint.proceed(args);
            long endTime = System.currentTimeMillis();
            long time = endTime - startTime;
            log.info("[result][info]日志记录，end...");
            addLog(joinPoint,mapper.writeValueAsString(result),time);
        } catch (Exception e) {
            log.error("[exception][error]日志记录异常信息: {}", e.getMessage());
            log.error("[exception][error][path]:{}.{}(), [cause]:'{}', [msg]:{}, stackTrace:",
                joinPoint.getSignature().getDeclaringTypeName(),
                joinPoint.getSignature().getName(),
                e.getCause() != null ? e.getCause() : "NULL",
                e.getMessage(),
                e);
            throw e;
        }
        return result;
    }

    /**
     * 日志记录入库操作
     */
    public void addLog(JoinPoint joinPoint, String outParams, long time) throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        HttpServletRequest request = ((ServletRequestAttributes)
                Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        log.info("\n\r=======================================\n\r" +
                        "请求地址:{} \n\r" +
                        "请求方式:{} \n\r" +
                        "请求类方法:{} \n\r" +
                        "请求方法参数:{} \n\r" +
                        "返回报文:{} \n\r" +
                        "处理耗时:{} ms \n\r" +
                        "=======================================\n\r",
                request.getRequestURI(),
                request.getMethod(),
                joinPoint.getSignature(),
//                JSONUtil.toJsonStr(filterArgs(joinPoint.getArgs())),
                mapper.writeValueAsString(filterArgs(joinPoint.getArgs())),
                outParams,
                String.valueOf(time)
        );
    }

    /**
     * 过滤参数
     * @param args
     * @return
     */
    private List<Object> filterArgs(Object[] args) {
        return Arrays.stream(args).filter(object -> !(object instanceof MultipartFilter)
                && !(object instanceof HttpServletRequest)
                && !(object instanceof HttpServletResponse)
        ).collect(Collectors.toList());
    }

}